/**
 * Copyright (C) Skywares Information Technology, LTD. 
 * All Rights Reserved.
 *
 * DynamicDataSourceAspect.java created on 2020年2月11日 下午4:36:53 by Lyon Lu 
 */
package com.mvc.server.dynamic.ds.config;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Stack;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import lombok.extern.log4j.Log4j2;

/**
 * <pre>
 * Description:
 * 
 * @author Lyon Lu
 * @date 2020年2月11日 下午4:36:53
 *
 * </pre>
 */
@Log4j2
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
@Component
public class DynamicDataSourceAspect {
	
	private ThreadLocal<Stack<String>> dsStack = new ThreadLocal<Stack<String>>();
	
	@Pointcut("@annotation(com.mvc.server.dynamic.ds.config.DataSource)")
    public void matchCondition() {}
	
	@Before("matchCondition()")
    public void doBefore(JoinPoint jp) 
    {
    	if (Objects.isNull(dsStack.get())) {
    		dsStack.set(new Stack<String>());
		}
    	
    	MethodSignature signature = (MethodSignature) jp.getSignature();
		Method method = signature.getMethod();
		DataSource ds = method.getAnnotation(DataSource.class);
		
		
		log.info("Method: {}.{}, DataSourceId: {} push -----------------------", signature.getDeclaringTypeName(),
				signature.getName(), ds.value());
		
    	dsStack.get().push(ds.value());
    	DynamicDataSourceContextHolder.setDataSourceKey(ds.value());
    }
	
	@Around("matchCondition()")
    public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
		log.info("methodAround   start------------------------------");
		
		Object result = proceedingJoinPoint.proceed();
		
		log.info("methodAround   end------------------------------");
		return result;
    }
	
	@After("matchCondition()")
    public void doAfter(JoinPoint jp) 
    {  
    	if (Objects.nonNull(dsStack.get()) && !dsStack.get().isEmpty()) {
    		
    		MethodSignature signature = (MethodSignature) jp.getSignature();
    		Method method = signature.getMethod();
    		DataSource ds = method.getAnnotation(DataSource.class);
    		
    		log.info("Method: {}.{}, DataSourceId: {} pop -----------------------", signature.getDeclaringTypeName(),
    				signature.getName(), ds.value());
    		
    		dsStack.get().pop();
		}
    	
    	String dataSourceId = null;
    	
    	if (Objects.nonNull(dsStack.get()) && !dsStack.get().isEmpty()) {
    		dataSourceId = dsStack.get().lastElement();
		}
    	
    	DynamicDataSourceContextHolder.setDataSourceKey(dataSourceId);
    }  
}
